import logging
from urllib import urlencode
from django.test import Client
from django.test.client import MULTIPART_CONTENT
import httplib2
from netifaces import interfaces, ifaddresses, AF_INET

logger = logging.getLogger(__name__)

def local_address():
    host_address = '127.0.0.1'
    for ifaceName in interfaces():
        addresses = [i['addr'] for i in ifaddresses(ifaceName).setdefault(AF_INET, [{'addr': None}] )]
        for addr in addresses:
            if addr != '127.0.0.1' and addr is not None:
                host_address = addr
    return host_address

from django.conf import settings

class LoggingClient(Client):
    def head(self, path, data={}, follow=False, **extra):
        logger.info("HEAD: " + path + str(data) + ", Follow:" + str(follow) + ", Headers: " + str(extra))
        response =  super(LoggingClient, self).head(path, data, follow, **extra)
        logger.info("Response: status_code:" +  str(response.status_code) + ", content:" + response.content)
        return response

    def get(self, path, data={}, follow=False, **extra):
        logger.info("GET: " + path + str(data) + ", Follow:" + str(follow) + ", Headers: " + str(extra))
        response =  super(LoggingClient, self).get(path, data, follow, **extra)
        logger.info("Response: status_code:" +  str(response.status_code) + ", content:" + response.content)
        return response

    def post(self, path, data={}, content_type=MULTIPART_CONTENT, follow=False, **extra):
        logger.info("POST: " + path + ", Content:" + str(data) + ", Content_type = " + content_type + ", Follow:" + str(follow) + " , Headers: " + str(extra))
        response =  super(LoggingClient, self).post(path, data, content_type, follow, **extra)
        logger.info("Response: status_code:" +  str(response.status_code) + ", content:" + response.content)
        return response

    def delete(self, path, data={}, follow=False, **extra):
        logger.info("DELETE: " + path + str(data) + ", Follow:" + str(follow) + ", Headers: " + str(extra))
        response =  super(LoggingClient, self).delete(path, data, follow, **extra)
        logger.info("Response: status_code:" +  str(response.status_code) + ", content:" + response.content)
        return response

    def put(self, path, data={}, content_type=MULTIPART_CONTENT, follow=False, **extra):
        logger.info("PUT: " + path + ", Content:" + str(data) + ", Content_type = " + content_type + ", Follow:" + str(follow) + " , Headers: " + str(extra))
        response =  super(LoggingClient, self).put(path, data, content_type, follow, **extra)
        logger.info("Response: status_code:" +  str(response.status_code) + ", content:" + response.content)
        return response

class Response(object):
    status_code = 200
    content = ''
    headers = {}

    def __init__(self, response, content):
        self.status_code = response.status
        self.content = content
        self.headers = response

    def __getitem__(self, key): return self.headers[key.lower()]
    def __len__(self,key): return len(self.headers)


def get_test_server_url():
    try:
        return 'http://' + settings.TEST_SERVER + ':' + settings.TEST_PORT
    except:
        return 'http://localhost:8000'

class ExternalCallingClient(Client):
    url = get_test_server_url()

    def build_url(self, path, parameters = {}):
        new_url = self.url + path
        separator = '?'
        for key, value in parameters.iteritems():
            new_url = new_url + separator + urlencode(key) + '=' + urlencode(value)
            separator = '&'
        logger.info("URL to call: " + new_url)
        return new_url

    def head(self, path, data={}, follow=False, **extra):
        logger.info("HEAD: " + path + str(data) + ", Follow:" + str(follow) + ", Headers: " + str(extra))
        h = httplib2.Http()
        resp, content = h.request(self.build_url(path, data),'HEAD', headers=extra)
        response = Response(resp,content)
        logger.info("Response: status_code:" +  str(response.status_code) + ", content:" + response.content)
        return response

    def get(self, path, data={}, follow=False, **extra):
        logger.info("GET: " + path + str(data) + ", Follow:" + str(follow) + ", Headers: " + str(extra))
        h = httplib2.Http()
        resp, content = h.request(self.build_url(path, data),'GET', headers=extra)
        response = Response(resp,content)
        logger.info("Response: status_code:" +  str(response.status_code) + ", content:" + response.content)
        return response

    def post(self, path, data={}, content_type=MULTIPART_CONTENT, follow=False, **extra):
        logger.info("POST: " + path + ", Content:" + str(data) + ", Content_type = " + content_type + ", Follow:" + str(follow) + " , Headers: " + str(extra))
        h = httplib2.Http()
        if content_type == MULTIPART_CONTENT:
            resp, content = h.request(self.build_url(path),'POST', body = urlencode(data),headers=extra )
        else:
            resp, content = h.request(self.build_url(path),'POST', body = str(data), headers=extra)
        response = Response(resp,content)
        logger.info("Response: status_code:" +  str(response.status_code) + ", content:" + response.content)
        return response

    def delete(self, path, data={}, follow=False, **extra):
        logger.info("DELETE: " + path + ", Content:" + str(data) + ", Follow:" + str(follow) + ", Headers: " + str(extra))
        h = httplib2.Http()
        resp, content = h.request(self.build_url(path, data),'DELETE', headers=extra)
        response = Response(resp,content)
        logger.info("Response: status_code:" +  str(response.status_code) + ", content:" + response.content)
        return response

    def put(self, path, data={}, content_type=MULTIPART_CONTENT, follow=False, **extra):
        logger.info("PUT: " + path + str(data) + ", Content_type = " + content_type + ", Follow:" + str(follow) + " , Headers: " + str(extra))
        h = httplib2.Http()
        if content_type == MULTIPART_CONTENT:
            resp, content = h.request(self.build_url(path),'PUT', body = urlencode(data),headers=extra )
        else:
            resp, content = h.request(self.build_url(path),'PUT', body = str(data), headers=extra)
        response = Response(resp,content)
        logger.info("Response: status_code:" +  str(response.status_code) + ", content:" + response.content)
        return response


def debug_sql(function):
    ''' You can use this decorator if you want to see SQL queries printed during tests, as DEBUG is disabled
        during test execution
    '''
    def wrapper(request, *args, **kwargs):
        from django.conf import settings
        from django.db import connection
        settings.DEBUG = True
        connection.queries = []
        try:
            return function(request, *args, **kwargs)
        finally:
            settings.DEBUG = False
    return wrapper

